﻿using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Newtonsoft.Json;
using Sustainalytics.DataLayer.Shared;
using Sustainalytics.Entities;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Sustainalytics.DataLayer
{
    public partial class CompanyScreeningRepository
    {
        #region ResultOutput

        public void SaveResultOutput(Guid filterId, BsonArray resultOutput)
        {
            var coll = _clientMongoDb.GetCollection<BsonDocument>("ResultOutput");

            coll.DeleteMany(Builders<BsonDocument>.Filter.Eq("FilterId", filterId));

            if (resultOutput != null && resultOutput.Any())
            {
                coll.InsertMany(resultOutput.Select(x => BsonDocument.Create(x)));
            }
        }

        public List<CriteriaResultOutput> GetResultOutputByFilterId(Guid filterId)
        {
            var collection = _clientMongoDb.GetCollection<ResultOutput>("ResultOutput");

            if (collection == null)
                return new List<CriteriaResultOutput>();

            var query = collection.Find(Builders<ResultOutput>.Filter.Eq(x => x.FilterId, filterId)).FirstOrDefault();

            if (query == null)
                return new List<CriteriaResultOutput>();

            return JsonConvert.DeserializeObject<List<CriteriaResultOutput>>(query.Criteria);
        }

        public List<BsonDocument> GetResultOutput(ResultOutputFilter filter, int skip, int take, string[] orderBy = null,
             bool asc = true)
        {
            var coll = _clientMongoDb.GetCollection<ResultOutput>("ResultOutput");

            List<FilterDefinition<ResultOutput>> query = GetFilterDefinition(filter);

            SortDefinition<ResultOutput> mongoSortBy = null;
            if (orderBy != null)
            {
                mongoSortBy = orderBy.ToMongoSortBy<ResultOutput>(asc);
            }

            var cursor = coll.Find(Builders<ResultOutput>.Filter.And(query));
            if (mongoSortBy != null)
            {
                cursor = cursor.Sort(mongoSortBy);
            }
            cursor.Skip(skip);
            cursor.Limit(take);

            return cursor.ToList().Select(x => x.ToBsonDocument()).ToList();
        }

        public int CountResultOutput(ResultOutputFilter filter)
        {
            List<FilterDefinition<ResultOutput>> query = GetFilterDefinition(filter);

            var cursor = _clientMongoDb.GetCollection<ResultOutput>("ResultOutput");
            var count = (int)(cursor.Count(Builders<ResultOutput>.Filter.And(query)));

            return count;
        }

        private static List<FilterDefinition<ResultOutput>> GetFilterDefinition(ResultOutputFilter filter)
        {
            var query = new List<FilterDefinition<ResultOutput>>();

            if (filter != null && filter.FilterId.HasValue)
            {
                query.Add(Builders<ResultOutput>.Filter.Eq(x => x.FilterId, filter.FilterId.Value));
            }

            if (filter != null && filter.IsValid.HasValue)
            {
                if (filter.IsValid.Value == ResultIsValid.NAandNotValid)
                {
                    var q1 = Builders<ResultOutput>.Filter.Eq(x => x.IsValid, ResultIsValid.NotValid);
                    var q2 = Builders<ResultOutput>.Filter.Eq(x => x.IsValid, ResultIsValid.NotAvailable);

                    query.Add(Builders<ResultOutput>.Filter.Or(q1, q2));
                }
                else if (filter.IsValid.Value == ResultIsValid.NAandValid)
                {
                    var q1 = Builders<ResultOutput>.Filter.Eq(x => x.IsValid, ResultIsValid.Valid);
                    var q2 = Builders<ResultOutput>.Filter.Eq(x => x.IsValid, ResultIsValid.NotAvailable);

                    query.Add(Builders<ResultOutput>.Filter.Or(q1, q2));
                }
                else if (filter.IsValid.Value == ResultIsValid.ValidAndNotValid)
                {
                    var q1 = Builders<ResultOutput>.Filter.Eq(x => x.IsValid, ResultIsValid.Valid);
                    var q2 = Builders<ResultOutput>.Filter.Eq(x => x.IsValid, ResultIsValid.NotValid);
                    var q3 = Builders<ResultOutput>.Filter.Ne(x => x.IsValid, ResultIsValid.NotAvailable);

                    query.Add(Builders<ResultOutput>.Filter.And(Builders<ResultOutput>.Filter.Or(q1, q2), q3));
                }
                else
                {
                    query.Add(Builders<ResultOutput>.Filter.Eq(x => x.IsValid, filter.IsValid.Value));
                }
            }

            return query;
        }

        public List<BsonDocument> GetFullResultOutput(ResultOutputFilter filter)
        {
            var query = new List<FilterDefinition<BsonDocument>>
            {
                Builders<BsonDocument>.Filter.Eq("FilterId", filter.FilterId),
            };

            if (filter.IsValid.HasValue)
            {
                query.Add(Builders<BsonDocument>.Filter.Eq("IsValid", filter.IsValid));
            }

            var fields = new List<string>
            {
                "_id",
                "CompanyName",
                "CompanyId",
                "CompanyNameLowerCase",
                "Criteria",
                "IsValid"
            };

            List<BsonDocument> resPaged = _clientMongoDb.GetCollection<BsonDocument>("ResultOutput")
                .Find(Builders<BsonDocument>.Filter.And(query))
                .Project(Builders<BsonDocument>.Projection.Include(fields.ToArray()))
                .ToList();

            return resPaged;
        }

        public void DeleteResultOutput(Guid filterId)
        {
            var coll = _clientMongoDb.GetCollection<ResultOutput>("ResultOutput");

            coll.DeleteMany(Builders<ResultOutput>.Filter.Where(c => c.FilterId == filterId));
        }

        #endregion
    }
}
